# !/usr/bin/env python3
# coding=utf8
"""
回测模块会把回测结果写入文件夹,
此脚本会消费文件夹里的文件, 并将其转存到数据库,
"""
import vnpy.tools.database_cta
import vnpy.trader.utility
import vnpy_ctastrategy.backtesting

import datetime
import json
import logging
import pathlib
import sys
import time
from typing import Any, Dict, List, Set, Tuple, Type, Optional, Union, Callable, Sequence

from peewee import (
    AutoField,
    CharField,
    DateTimeField,
    IntegerField,
    FloatField,
    fn,
)
# http://docs.peewee-orm.com/en/latest/peewee/sqlite_ext.html#JSONField
# https://stackoverflow.com/questions/40553790/peewee-orm-jsonfield-for-mysql
# https://www.osgeo.cn/peewee/peewee/sqlite_ext.html
from playhouse.sqlite_ext import (
    SqliteExtDatabase,
    JSONField,
)


def consumer(database: vnpy.tools.database_cta.CtaBacktestDatabase) -> int:
    """
    从文件夹消费文件并转存到数据库, 并返回消费的文件的个数,
    """
    folder: pathlib.Path = vnpy.trader.utility.get_folder_path(vnpy_ctastrategy.backtesting.CTA_BACKTEST_RESULT_BF)

    # 暂时认为所有json文件都需要被消费,
    files: List[pathlib.Path] = [_ for _ in folder.glob("*.json") if _.is_file()]
    files.sort()

    # 如果能找到消费文件, 就打印日志, 否则不打印日志, 防止日志文件过大,
    files and logging.info(f"folder={folder}, len_files={len(files)},")

    # 内容正常的json文件转换成类对象, 并缓存文件和对象,
    cache: Dict[pathlib.Path, dict] = {}

    for file in files:
        file: pathlib.Path = file

        line: Optional[vnpy.tools.database_cta.CtaStatisticsData] = None

        try:
            text: bytes = file.read_bytes()
            data: dict = json.loads(s=text)
            assert isinstance(data, dict)
            line = vnpy.tools.database_cta.CtaStatisticsData.dict2py(data)
        except Exception as ex:
            logging.info(f"file={file}, ex={ex},")
            continue

        cache[file] = line

    files and logging.info(f"len_cache={len(cache)},")

    # 类对象批量写入数据库,
    lines: List[vnpy.tools.database_cta.CtaStatisticsData] = [*cache.values()]

    save_ok: Optional[bool] = None
    save_ex: Optional[Exception] = None
    try:
        database.save_cta_statistics_data(lines=lines)
        save_ok = True
    except Exception as ex:
        save_ok, save_ex = False, ex

    files and logging.info(f"save_ok={save_ok}, save_ex={save_ex},")

    # 清理成功消费的文件,
    if save_ok:
        for file in cache.keys():
            file.unlink(missing_ok=True)

    # 返回消费的文件的个数
    return len(cache) if save_ok else 0


if __name__ == "__main__":
    logging.basicConfig(
        filename=f"{__file__}.log", filemode='a', level=logging.INFO,
        format="%(asctime)s (%(process)5d, %(thread)d) %(name)s %(levelname)s - %(message)s",
    )

    logging.info(f"++++++++++ START ++++++++++")

    database: vnpy.tools.database_cta.CtaBacktestDatabase = vnpy.tools.database_cta.get_database()

    consume_pit: Optional[datetime.datetime] = None  # point-in-time
    consume_cnt: int = 0

    while True:
        cnt: int = consumer(database)
        if cnt != 0:
            consume_pit: datetime.datetime = datetime.datetime.now()
            consume_cnt: int = cnt

        message: str = "\r{}, pit={}, cnt={}".format(
            datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f"),
            consume_pit.strftime("%Y-%m-%d %H:%M:%S") if consume_pit else ('_' * 19),
            f"{consume_cnt:<9d}",
        )
        sys.stdout.write(message)

        time.sleep(2)
    pass

    '''
    # 或许可以根据这个命令, 定位信息, 然后手动修改SQLite文件的名字:
    sqlite3 -table database_cta_bf.db "SELECT strategy_name,exchange,symbol,interval,start,end,COUNT(*) FROM dbctabacktestdata GROUP BY strategy_name,exchange,symbol,interval,start,end;"
    '''
